//////////////////////////////////////////////////
// EASIM project
// easim.omar.Node
// 6/17/2007 5:48 PM
// Cong Liu
// gzcong@gmail.com

// Copyright (C) 2007
// All rights reserved.
// Refer to LICENSE of JIST (Java In Simulation Time) for terms and conditions of use.

package easim.omar;

import easim.net.DtnNodeInterface;
import easim.net.DtnNode;
import easim.net.Clock;

import jist.swans.Constants;
import jist.swans.misc.Message;
import jist.runtime.JistAPI.DoNotRewrite;

public class Node extends DtnNode implements DoNotRewrite
{

  public static final int MESSAGE_SIZE_MIN = 512;
  public static final int MESSAGE_SIZE_MAX = 2048;

  /** class OmarMessage */
  public static class OmarMessage implements Message, DoNotRewrite
  {
    public DTDV.UpdateMessage dtdvMsg;
    public ACK.UpdateMessage ackMsg;
    public Vector.UpdateMessage vectorMsg;
    public Data.DataMessage dataMsg;
    public int getSize() {
      int size = 0;
      if (dtdvMsg != null) {
        size += dtdvMsg.getSize();
      }
      if (ackMsg != null) {
        size += ackMsg.getSize();
      }
      if (vectorMsg != null) {
        size += vectorMsg.getSize();
      }
      if (dataMsg != null) {
        size += dataMsg.getSize();
      }
      return size;
    }
    public void getBytes(byte[] msg, int offset) {
      throw new RuntimeException("no implementation.");
    }
  } // end class OmarMessage

  public DTDV dtdv;
  public ACK ack;
  public Vector vector;
  public Data data;
  public TimeStats timeStats;

  public Node(int id) {
    super(id);
    dtdv = new DTDV(this);
    ack = new ACK(this);
    vector = new Vector(this);
    data = new Data(this);
    timeStats = new TimeStats(this);
  }

  public Message nextMessageToSend() {
    //System.out.println("nextMessageToSend time = " + Clock.getTime());
    OmarMessage msg = new OmarMessage();
    if (msg.getSize() < MESSAGE_SIZE_MIN) {
      msg.dtdvMsg = (DTDV.UpdateMessage)dtdv.nextMessageToSend();
      if (msg.dtdvMsg != null) {
        timeStats.incDtdvMsg(msg.dtdvMsg.getSize());
      }
    }
    if (msg.getSize() < MESSAGE_SIZE_MIN) {
      msg.ackMsg = (ACK.UpdateMessage)ack.nextMessageToSend();
    }
    if (msg.getSize() < MESSAGE_SIZE_MIN) {
      msg.vectorMsg = (Vector.UpdateMessage)vector.nextMessageToSend();
    }
    if (msg.getSize() < MESSAGE_SIZE_MIN) {
      msg.dataMsg = (Data.DataMessage)data.nextMessageToSend();
    }
    if (msg.getSize() > 0) {
      ++ Stats.send.omarMsgs;
      Stats.send.omarMsgSize += msg.getSize();
      return msg;
    }
    return null;
  }

  public void receiveMessage(Message message, int srcId) {
    OmarMessage msg = (OmarMessage)message;
    if (msg.dtdvMsg != null) {
      dtdv.receiveMessage(msg.dtdvMsg, srcId);
    }
    if (msg.ackMsg != null) {
      ack.receiveMessage(msg.ackMsg, srcId);
    }
    if (msg.vectorMsg != null) {
      vector.receiveMessage(msg.vectorMsg, srcId);
    }
    if (msg.dataMsg != null) {
      data.receiveMessage(msg.dataMsg, srcId);
    }
  }

  public void onAckMessage(Message message) {
    OmarMessage msg = (OmarMessage)message;
    ++ Stats.recv.omarMsgs;
    Stats.recv.omarMsgSize += msg.getSize();
    if (msg.dtdvMsg != null) {
      dtdv.onAckMessage(msg.dtdvMsg);
    }
    if (msg.ackMsg != null) {
      ack.onAckMessage(msg.ackMsg);
    }
    if (msg.vectorMsg != null) {
      vector.onAckMessage(msg.vectorMsg);
    }
    if (msg.dataMsg != null) {
      data.onAckMessage(msg.dataMsg);
    }
  }

  public void onDropMessage(Message message, int[] dstIds) {
    OmarMessage msg = (OmarMessage)message;
    if (msg.dtdvMsg != null) {
      dtdv.onDropMessage(msg.dtdvMsg, dstIds);
    }
    if (msg.ackMsg != null) {
      ack.onDropMessage(msg.ackMsg, dstIds);
    }
    if (msg.vectorMsg != null) {
      vector.onDropMessage(msg.vectorMsg, dstIds);
    }
    if (msg.dataMsg != null) {
      data.onDropMessage(msg.dataMsg, dstIds);
    }
  }

  public void onContactDetected(int id) {
    dtdv.onContactDetected(id);
    ack.onContactDetected(id);
    vector.onContactDetected(id);
    data.onContactDetected(id);
  }

  public void onContactBroken(int id) {
    dtdv.onContactBroken(id);
    ack.onContactBroken(id);
    vector.onContactBroken(id);
    data.onContactBroken(id);
  }

  public String toString() {
    return id + "(" + x + "," + y + ")\r\n" + 
      dtdv + "\r\n" + 
      ack + "\r\n" + 
      vector + "\r\n" + 
      data;
  }

}
